﻿using IOA.MES.Business;
using IOA.MES.Common;
using IOA.Utils;
using Newtonsoft.Json;
using NLog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;

namespace IOA.MES.Web.App_Start
{
    public class CommonFilter : ActionFilterAttribute, IActionFilter
    {
        private Logger logger = LogManager.GetCurrentClassLogger();
        private Stopwatch watcher;
        private object lockObj = new object();

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            watcher = new Stopwatch();
            watcher.Start();
            if (!new[] { "/auth/login", "/auth/getlang", "/auth/logout" }.Contains(filterContext.HttpContext.Request.Url.AbsolutePath.ToLower().Trim()))
            {
                var token = HttpContext.Current.Request.Cookies["Token"]?.Value;
                var userToken = new UserMgr().GetToken(token);
                if (userToken == null || userToken.Expires < DateTime.Now)
                {
                    new FormsAuthenticationService().SignOut();
                    filterContext.Result = new JsonResult { Data = new ResultJson<object> { ErrCode = 403, ErrMsg = "登录已过期" }, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
                }
            }

            base.OnActionExecuting(filterContext);
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            watcher.Stop();
            var request = HttpContext.Current.Request;
            var dictLog = new Dictionary<string, object>();
            dictLog.Add("Url", request.Url.AbsolutePath.ToString());
            dictLog.Add("Elapsed", watcher.ElapsedMilliseconds);
            dictLog.Add("QueryStrings", string.Join("&", request.QueryString.AllKeys.Select(_ => $"{_}={request.QueryString[_]}")));

            if (string.Equals(HttpContext.Current.Request.HttpMethod, "GET", StringComparison.CurrentCultureIgnoreCase))
            {
                if (filterContext.Exception != null)
                {
                    logger.Fatal(filterContext.Exception, JsonConvert.SerializeObject(dictLog));
                }
                base.OnActionExecuted(filterContext);
                return;
            }

            HttpContext.Current.Request.InputStream.Position = 0;
            var length = HttpContext.Current.Request.InputStream.Length;
            var buffer = new byte[length];
            HttpContext.Current.Request.InputStream.Read(buffer, 0, (int)length);
            dictLog.Add("Body", request.Url.AbsolutePath.ToString().ToLower().Contains("common/upload") ? "文件对象" : Encoding.UTF8.GetString(buffer));

            if (filterContext.Exception == null)
            {
                logger.Info(JsonConvert.SerializeObject(dictLog));
            }
            else
            {
                try
                {
                    lock (lockObj)
                    {
                        if (BaseEnv.LangPackages == null || !BaseEnv.LangPackages.Any())
                        {
                            BaseEnv.LangPackages = new List<LangPackage>();
                            var langFiles = Directory.GetFiles($"{AppDomain.CurrentDomain.BaseDirectory}res\\errlang");
                            var sortedFiles = new List<string>();
                            if (langFiles.Any(_ => StringUtils.Equals(Path.GetFileNameWithoutExtension(_), "vn")))
                            {
                                sortedFiles.Add(langFiles.FirstOrDefault(_ => StringUtils.Equals(Path.GetFileNameWithoutExtension(_), "vn")));
                            }
                            if (langFiles.Any(_ => StringUtils.Equals(Path.GetFileNameWithoutExtension(_), "zh_CN")))
                            {
                                sortedFiles.Add(langFiles.FirstOrDefault(_ => StringUtils.Equals(Path.GetFileNameWithoutExtension(_), "zh_CN")));
                            }
                            if (langFiles.Any(_ => StringUtils.Equals(Path.GetFileNameWithoutExtension(_), "en")))
                            {
                                sortedFiles.Add(langFiles.FirstOrDefault(_ => StringUtils.Equals(Path.GetFileNameWithoutExtension(_), "en")));
                            }
                            foreach (var langFile in sortedFiles)
                            {
                                var jsonStr = File.ReadAllText(langFile, Encoding.UTF8);
                                BaseEnv.LangPackages.Add(JsonConvert.DeserializeObject<LangPackage>(jsonStr));
                            }
                        }
                    }

                    var errMsg = filterContext.Exception.Message;

                    var response = new ResultJson<object>(500, "ErrCode:500\r\n服务器忙\r\nServer Error\r\nLỗi máy chủ");
                    if (filterContext.Exception is MultiLanBizException)
                    {
                        var bizException = filterContext.Exception as MultiLanBizException;
                        dictLog.Add("ErrCode", bizException.ErrCode);

                        var sbMsg = new StringBuilder();
                        foreach (var lang in BaseEnv.LangPackages)
                        {
                            var err = lang.package.FirstOrDefault(_ => _.Key == bizException.ErrCode);
                            if (err.Value != null)
                            {
                                sbMsg.AppendLine(err.Value);
                            }
                        }
                        errMsg = sbMsg.ToString().TrimEnd(new[] { '\r', '\n' }) + (string.IsNullOrWhiteSpace(bizException.ErrParas) ? string.Empty : $"：\r\n{bizException.ErrParas}");
                        response = new ResultJson<object>(bizException.ErrCode, $"ErrCode:{bizException.ErrCode}\r\n{errMsg}");
                    }
                    dictLog.Add("ErrMsg", errMsg);

                    filterContext.Result = new JsonResult { Data = response };

                    if (response.ErrCode != 500)
                    {
                        logger.Info(JsonConvert.SerializeObject(dictLog));
                    }
                    else
                    {
                        logger.Fatal(filterContext.Exception, JsonConvert.SerializeObject(dictLog));
                    }

                    filterContext.Exception = null;
                    filterContext.ExceptionHandled = true;
                }
                catch (Exception ex)
                {
                    logger.Fatal(ex, "OnActionExecutedError");
                }
            }
            base.OnActionExecuted(filterContext);
        }
    }
}
